package cn.iocoder.yudao.module.system.service.gugu;

import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.MajorRecommendItemVO;
import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.MajorRecommendReqVO;
import cn.iocoder.yudao.module.system.controller.admin.gugu.vo.MajorRecommendRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.college.CollegeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.collegeenrollmentplan.CollegeEnrollmentPlanDO;
import cn.iocoder.yudao.module.system.dal.dataobject.gugu.CeeMajorDO;
import cn.iocoder.yudao.module.system.dal.dataobject.gugu.MajorAdmissionDO;
import cn.iocoder.yudao.module.system.dal.dataobject.gugu.ScoreSegmentDO;
import cn.iocoder.yudao.module.system.dal.mysql.college.CollegeMapper;
import cn.iocoder.yudao.module.system.dal.mysql.collegeenrollmentplan.CollegeEnrollmentPlanMapper;
import cn.iocoder.yudao.module.system.dal.mysql.gugu.CeeMajorMapper;
import cn.iocoder.yudao.module.system.dal.mysql.gugu.MajorAdmissionMapper;
import cn.iocoder.yudao.module.system.dal.mysql.gugu.ScoreSegmentMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 智能推荐专业服务实现类
 *
 * @author 芋道源码
 */
@Service
@Slf4j
public class MajorRecommendationServiceImpl implements MajorRecommendationService {

    @Resource
    private MajorAdmissionMapper majorAdmissionMapper;

    @Resource
    private CeeMajorMapper ceeMajorMapper;

    @Resource
    private CollegeMapper collegeMapper;

    @Resource
    private CollegeEnrollmentPlanMapper collegeEnrollmentPlanMapper;

    @Resource
    private ScoreSegmentMapper scoreSegmentMapper;

    @Override
    public MajorRecommendRespVO recommendMajors(MajorRecommendReqVO reqVO) {
        return recommendMajors(reqVO, null);
    }

    @Override
    public MajorRecommendRespVO recommendMajors(MajorRecommendReqVO reqVO, Long userId) {
        log.info("开始智能推荐专业，用户ID：{}，省份：{}，分数：{}，位次：{}", 
                userId, reqVO.getProvince(), reqVO.getScore(), reqVO.getRanks());

        long startTime = System.currentTimeMillis();

        try {
            // 1. 参数预处理
            Integer userRank = reqVO.getRanks();
            if (userRank == null) {
                // 如果没有提供位次，根据分数和一分一段表计算位次
                userRank = calculateRankByScore(reqVO.getScore(), reqVO.getProvince(), reqVO.getYear(), reqVO.getClassify());
            }

            // 2. 根据选科要求筛选可报考的专业
            List<String> subjectList = Arrays.asList(reqVO.getSubjects().split(","));
            List<String> availableMajors = filterMajorsBySubjects(subjectList, reqVO.getProvince(), 
                    reqVO.getYear(), reqVO.getClassify(), reqVO.getBatch());

            // 3. 获取专业录取数据
            List<MajorAdmissionDO> candidateMajors = getMajorAdmissionData(reqVO, availableMajors);

            // 4. 计算推荐结果
            List<MajorRecommendItemVO> allRecommendations = new ArrayList<>();
            int chongCount = 0, wentuoCount = 0, baodiCount = 0;

            for (MajorAdmissionDO major : candidateMajors) {
                try {
                    // 计算录取概率
                    Double probability = calculateMajorAdmissionProbability(userRank, major.getSchoolUuid(), 
                            major.getMajorName(), reqVO.getProvince(), reqVO.getYear(), reqVO.getClassify());

                    if (probability == null || probability < 10) {
                        continue; // 概率过低，不推荐
                    }

                    // 判断推荐类型
                    String type = determineRecommendationType(probability);

                    // 构建推荐项
                    MajorRecommendItemVO item = buildRecommendationItem(major, probability, type, reqVO);
                    if (item != null) {
                        allRecommendations.add(item);

                        // 统计各类型数量
                        switch (type) {
                            case "CHONG":
                                chongCount++;
                                break;
                            case "WENTUO":
                                wentuoCount++;
                                break;
                            case "BAODI":
                                baodiCount++;
                                break;
                        }
                    }
                } catch (Exception e) {
                    log.warn("处理专业推荐时发生异常：{}，专业：{}", e.getMessage(), major.getMajorName());
                }
            }

            // 5. 排序和筛选
            allRecommendations = sortAndFilterRecommendations(allRecommendations, reqVO);

            // 6. 分页处理
            int total = allRecommendations.size();
            int startIndex = (reqVO.getPageNum() - 1) * reqVO.getPageSize();
            int endIndex = Math.min(startIndex + reqVO.getPageSize(), total);
            List<MajorRecommendItemVO> pageList = allRecommendations.subList(startIndex, endIndex);

            // 7. 构建响应结果
            MajorRecommendRespVO respVO = buildResponse(pageList, reqVO, total, chongCount, wentuoCount, baodiCount, userRank);

            long endTime = System.currentTimeMillis();
            log.info("智能推荐专业完成，耗时：{}ms，推荐专业总数：{}", endTime - startTime, total);

            return respVO;

        } catch (Exception e) {
            log.error("智能推荐专业发生异常", e);
            throw new RuntimeException("推荐服务异常：" + e.getMessage());
        }
    }

    @Override
    public Double calculateMajorAdmissionProbability(Integer userRank, String schoolUuid, String majorName, 
                                                   String province, Integer year, String examType) {
        try {
            // 1. 获取近3年该专业的录取数据
            List<MajorAdmissionDO> historyData = majorAdmissionMapper.selectBySchoolAndMajor(
                    schoolUuid, majorName, province, Arrays.asList(year - 2, year - 1, year));

            if (historyData.isEmpty()) {
                return null;
            }

            // 2. 计算历年录取位次
            List<Integer> admissionRanks = new ArrayList<>();
            for (MajorAdmissionDO data : historyData) {
                if (StringUtils.hasText(data.getLowestSection())) {
                    try {
                        admissionRanks.add(Integer.parseInt(data.getLowestSection()));
                    } catch (NumberFormatException e) {
                        log.warn("位次数据格式错误：{}", data.getLowestSection());
                    }
                }
            }

            if (admissionRanks.isEmpty()) {
                return null;
            }

            // 3. 计算概率
            return calculateProbabilityByRank(userRank, admissionRanks);

        } catch (Exception e) {
            log.error("计算专业录取概率失败", e);
            return null;
        }
    }

    @Override
    public String determineRecommendationType(Double probability) {
        if (probability >= 80) {
            return "BAODI";  // 保底
        } else if (probability >= 50) {
            return "WENTUO"; // 稳妥
        } else {
            return "CHONG";  // 冲刺
        }
    }

    @Override
    public String generateMajorRecommendationReason(String schoolName, String majorName, Double probability, 
                                                  String type, List<String> majorTags) {
        StringBuilder reason = new StringBuilder();
        
        switch (type) {
            case "CHONG":
                reason.append("冲刺推荐：");
                reason.append(String.format("%s的%s专业录取概率为%.1f%%，", schoolName, majorName, probability));
                reason.append("虽然有一定挑战性，但值得尝试。");
                break;
            case "WENTUO":
                reason.append("稳妥推荐：");
                reason.append(String.format("%s的%s专业录取概率为%.1f%%，", schoolName, majorName, probability));
                reason.append("录取把握较大，是理想的选择。");
                break;
            case "BAODI":
                reason.append("保底推荐：");
                reason.append(String.format("%s的%s专业录取概率为%.1f%%，", schoolName, majorName, probability));
                reason.append("录取概率很高，可作为保底选择。");
                break;
        }

        // 添加专业特色
        if (majorTags != null && !majorTags.isEmpty()) {
            reason.append("该专业具有").append(String.join("、", majorTags)).append("等特点。");
        }

        return reason.toString();
    }

    @Override
    public Integer calculateRankByScore(Integer score, String province, Integer year, String examType) {
        try {
            log.debug("开始根据分数计算位次：分数={}, 省份={}, 年份={}, 考试类型={}", score, province, year, examType);

            // 查询一分一段数据
            List<ScoreSegmentDO> segments = scoreSegmentMapper.selectByProvinceYearAndType(province, year.toString(), examType);

            if (segments == null || segments.isEmpty()) {
                log.warn("未找到一分一段数据：省份={}, 年份={}, 考试类型={}", province, year, examType);
                return null;
            }

            // 按分数从高到低排序（确保数据顺序正确）
            segments.sort((a, b) -> {
                try {
                    Integer scoreA = parseScoreFromRange(a.getExaminationScore());
                    Integer scoreB = parseScoreFromRange(b.getExaminationScore());
                    if (scoreA == null && scoreB == null) return 0;
                    if (scoreA == null) return 1;
                    if (scoreB == null) return -1;
                    return scoreB.compareTo(scoreA); // 从高到低排序
                } catch (Exception e) {
                    return 0;
                }
            });

            // 查找用户分数对应的位次
            for (ScoreSegmentDO segment : segments) {
                if (isScoreInRange(score, segment.getExaminationScore())) {
                    Integer rank = parseRankFromRange(segment.getRankingRange());
                    log.debug("找到精确匹配的分数段：{}, 位次范围：{}, 返回位次：{}", segment.getExaminationScore(), segment.getRankingRange(), rank);
                    return rank;
                }
            }

            // 如果没有找到精确匹配，找到第一个分数小于等于用户分数的分数段
            for (ScoreSegmentDO segment : segments) {
                Integer segmentScore = parseScoreFromRange(segment.getExaminationScore());
                if (segmentScore != null && segmentScore <= score) {
                    Integer rank = parseRankFromRange(segment.getRankingRange());
                    log.debug("找到小于等于用户分数的分数段：{}, 位次范围：{}, 返回位次：{}", segment.getExaminationScore(), segment.getRankingRange(), rank);
                    return rank;
                }
            }

            // 如果用户分数高于所有分数段，返回最高分数段的位次
            if (!segments.isEmpty()) {
                ScoreSegmentDO highestSegment = segments.get(0);
                Integer rank = parseRankFromRange(highestSegment.getRankingRange());
                log.debug("用户分数高于所有分数段，返回最高分数段位次范围：{}, 返回位次：{}", highestSegment.getRankingRange(), rank);
                return rank;
            }

        } catch (Exception e) {
            log.error("根据分数计算位次失败：分数={}, 省份={}, 年份={}, 考试类型={}", score, province, year, examType, e);
        }

        return null;
    }

    @Override
    public List<String> filterMajorsBySubjects(List<String> subjects, String province, Integer year, 
                                             String examType, String batch) {
        // TODO: 实现基于选科要求的专业筛选
        // 这里暂时返回所有专业，实际应该根据选科要求筛选
        return new ArrayList<>();
    }

    @Override
    public List<String> getMajorTags(String majorName, String schoolUuid) {
        List<String> tags = new ArrayList<>();
        
        // 根据专业名称添加标签
        if (majorName.contains("计算机") || majorName.contains("软件") || majorName.contains("人工智能")) {
            tags.add("热门专业");
            tags.add("就业前景好");
        }
        
        if (majorName.contains("医学") || majorName.contains("临床")) {
            tags.add("专业性强");
            tags.add("社会需求大");
        }
        
        return tags;
    }

    @Override
    public List<String> getSchoolTags(String schoolUuid) {
        List<String> tags = new ArrayList<>();
        
        // 查询学校信息获取标签
        CollegeDO college = collegeMapper.selectBySchoolUuid(schoolUuid);
        if (college != null) {
            // 根据学校属性添加标签
            if (college.getIs985() != null && college.getIs985()) {
                tags.add("985");
            }
            if (college.getIs211() != null && college.getIs211()) {
                tags.add("211");
            }
            if (college.getIsDualClass() != null && college.getIsDualClass()) {
                tags.add("双一流");
            }

            // 根据学校类型添加标签
            if (college.getCollegeType() != null) {
                tags.add(college.getCollegeType());
            }
        }
        
        return tags;
    }

    /**
     * 获取专业录取数据
     */
    private List<MajorAdmissionDO> getMajorAdmissionData(MajorRecommendReqVO reqVO, List<String> availableMajors) {
        // 构建查询条件
        String majorKeyword = reqVO.getMajorKeyword();
        Integer minScore = reqVO.getMinScore() != null ? reqVO.getMinScore() : reqVO.getScore() - 20;
        Integer maxScore = reqVO.getMaxScore() != null ? reqVO.getMaxScore() : reqVO.getScore() + 20;

        if (StringUtils.hasText(majorKeyword)) {
            // 按专业关键词查询
            return majorAdmissionMapper.selectByProvinceYearScoreRangeAndMajorKeywords(
                    reqVO.getProvince(), reqVO.getYear(), minScore, maxScore, majorKeyword);
        } else {
            // 查询所有符合分数范围的专业
            return majorAdmissionMapper.selectByProvinceYearAndScoreRange(
                    reqVO.getProvince(), reqVO.getYear(), minScore, maxScore);
        }
    }

    /**
     * 构建推荐项
     */
    private MajorRecommendItemVO buildRecommendationItem(MajorAdmissionDO major, Double probability, 
                                                       String type, MajorRecommendReqVO reqVO) {
        MajorRecommendItemVO item = new MajorRecommendItemVO();
        
        // 基本信息
        item.setMajorName(major.getMajorName());
        item.setMajorCode(major.getMajorCode());
        item.setSchoolUuid(major.getSchoolUuid());
        item.setSchoolName(major.getSchoolName());
        item.setEnrollProbability(probability.intValue());
        item.setType(type);
        item.setTypeDesc(getTypeDescription(type));
        
        // 获取专业详情
        CeeMajorDO majorDetail = ceeMajorMapper.selectByMajorName(major.getMajorName()).stream().findFirst().orElse(null);
        if (majorDetail != null) {
            item.setDisciplinaryCategory(majorDetail.getDisciplinaryCategory());
            item.setDisciplinarySubCategory(majorDetail.getDisciplinarySubCategory());
            
            // 构建专业详情
            MajorRecommendItemVO.MajorDetailVO detail = new MajorRecommendItemVO.MajorDetailVO();
            detail.setIntroduction(majorDetail.getMajorIntroduction());
            detail.setCareerDirection(majorDetail.getCareerDirection());
            detail.setGraduateScale(majorDetail.getGraduateScale());
            detail.setMaleFemaleRatio(majorDetail.getMaleFemaleRatio());
            detail.setRecommendSchools(majorDetail.getRecommendSchools());
            item.setMajorDetail(detail);
        }
        
        // 获取标签
        item.setMajorTags(getMajorTags(major.getMajorName(), major.getSchoolUuid()));
        item.setSchoolTags(getSchoolTags(major.getSchoolUuid()));
        
        // 生成推荐理由
        item.setReason(generateMajorRecommendationReason(major.getSchoolName(), major.getMajorName(), 
                probability, type, item.getMajorTags()));
        
        // 设置排序权重
        item.setSortWeight(calculateSortWeight(probability, type));
        
        return item;
    }

    /**
     * 判断分数是否在指定的分数范围内
     *
     * @param score 用户分数
     * @param scoreRange 分数范围字符串，可能是单一分数（如"650"）或区间（如"650-660"）
     * @return 是否在范围内
     */
    private boolean isScoreInRange(Integer score, String scoreRange) {
        if (score == null || scoreRange == null || scoreRange.trim().isEmpty()) {
            return false;
        }

        try {
            if (scoreRange.contains("-")) {
                // 处理区间分数，如 "650-660"
                String[] parts = scoreRange.split("-");
                if (parts.length == 2) {
                    int minScore = Integer.parseInt(parts[0].trim());
                    int maxScore = Integer.parseInt(parts[1].trim());
                    return score >= minScore && score <= maxScore;
                }
            } else {
                // 处理单一分数，如 "650"
                int segmentScore = Integer.parseInt(scoreRange.trim());
                return score.equals(segmentScore);
            }
        } catch (NumberFormatException e) {
            log.warn("无法解析分数范围：{}", scoreRange);
        }

        return false;
    }

    /**
     * 从分数范围字符串中解析出分数值
     *
     * @param scoreRange 分数范围字符串，可能是单一分数（如"650"）或区间（如"650-660"）
     * @return 解析出的分数值，对于区间返回最高分数
     */
    private Integer parseScoreFromRange(String scoreRange) {
        if (scoreRange == null || scoreRange.trim().isEmpty()) {
            return null;
        }

        try {
            if (scoreRange.contains("-")) {
                // 处理区间分数，如 "650-660"，返回最高分数
                String[] parts = scoreRange.split("-");
                if (parts.length == 2) {
                    return Integer.parseInt(parts[1].trim());
                }
            } else {
                // 处理单一分数，如 "650"
                return Integer.parseInt(scoreRange.trim());
            }
        } catch (NumberFormatException e) {
            log.warn("无法解析分数范围：{}", scoreRange);
        }

        return null;
    }

    /**
     * 从位次范围字符串中解析出最大位次值
     *
     * @param rankingRange 位次范围字符串，格式如"2090-2194"或单一位次"2090"
     * @return 解析出的最大位次值
     */
    private Integer parseRankFromRange(String rankingRange) {
        if (rankingRange == null || rankingRange.trim().isEmpty()) {
            return null;
        }

        try {
            if (rankingRange.contains("-")) {
                // 处理位次区间，如 "2090-2194"，返回最大位次
                String[] parts = rankingRange.split("-");
                if (parts.length == 2) {
                    return Integer.parseInt(parts[1].trim());
                }
            } else {
                // 处理单一位次，如 "2090"
                return Integer.parseInt(rankingRange.trim());
            }
        } catch (NumberFormatException e) {
            log.warn("无法解析位次范围：{}", rankingRange);
        }

        return null;
    }

    /**
     * 根据位次计算概率
     */
    private Double calculateProbabilityByRank(Integer userRank, List<Integer> admissionRanks) {
        if (admissionRanks.isEmpty()) {
            return null;
        }
        
        // 计算历年录取位次的统计信息
        Collections.sort(admissionRanks);
        int minRank = admissionRanks.get(0);
        int maxRank = admissionRanks.get(admissionRanks.size() - 1);
        double avgRank = admissionRanks.stream().mapToInt(Integer::intValue).average().orElse(0);
        
        // 基于位次差异计算概率
        if (userRank <= minRank) {
            return 95.0; // 位次优于历年最低录取位次
        } else if (userRank <= avgRank) {
            return 80.0 - (userRank - minRank) * 30.0 / (avgRank - minRank);
        } else if (userRank <= maxRank) {
            return 50.0 - (userRank - avgRank) * 30.0 / (maxRank - avgRank);
        } else {
            // 位次低于历年最高录取位次，概率较低
            double ratio = (double) (userRank - maxRank) / maxRank;
            return Math.max(10.0, 20.0 - ratio * 10.0);
        }
    }

    /**
     * 获取类型描述
     */
    private String getTypeDescription(String type) {
        switch (type) {
            case "CHONG":
                return "冲刺";
            case "WENTUO":
                return "稳妥";
            case "BAODI":
                return "保底";
            default:
                return "未知";
        }
    }

    /**
     * 计算排序权重
     */
    private Integer calculateSortWeight(Double probability, String type) {
        int baseWeight = 0;
        switch (type) {
            case "BAODI":
                baseWeight = 300;
                break;
            case "WENTUO":
                baseWeight = 200;
                break;
            case "CHONG":
                baseWeight = 100;
                break;
        }
        return baseWeight + probability.intValue();
    }

    /**
     * 排序和筛选推荐结果
     */
    private List<MajorRecommendItemVO> sortAndFilterRecommendations(List<MajorRecommendItemVO> recommendations, 
                                                                  MajorRecommendReqVO reqVO) {
        // 按排序权重降序排列
        recommendations.sort((a, b) -> b.getSortWeight().compareTo(a.getSortWeight()));
        
        // 应用筛选条件
        if (StringUtils.hasText(reqVO.getType())) {
            recommendations = recommendations.stream()
                    .filter(item -> reqVO.getType().equals(item.getType()))
                    .collect(Collectors.toList());
        }
        
        if (StringUtils.hasText(reqVO.getDisciplinaryCategory())) {
            recommendations = recommendations.stream()
                    .filter(item -> reqVO.getDisciplinaryCategory().equals(item.getDisciplinaryCategory()))
                    .collect(Collectors.toList());
        }
        
        return recommendations;
    }

    /**
     * 构建响应结果
     */
    private MajorRecommendRespVO buildResponse(List<MajorRecommendItemVO> pageList, MajorRecommendReqVO reqVO, 
                                             int total, int chongCount, int wentuoCount, int baodiCount, Integer userRank) {
        MajorRecommendRespVO respVO = new MajorRecommendRespVO();
        
        // 分页信息
        respVO.setTotal((long) total);
        respVO.setList(pageList);
        respVO.setPageNum(reqVO.getPageNum());
        respVO.setPageSize(reqVO.getPageSize());
        respVO.setSize(pageList.size());
        respVO.setStartRow((reqVO.getPageNum() - 1) * reqVO.getPageSize() + 1);
        respVO.setEndRow(respVO.getStartRow() + pageList.size() - 1);
        respVO.setPages((int) Math.ceil((double) total / reqVO.getPageSize()));
        respVO.setPrePage(reqVO.getPageNum() > 1 ? reqVO.getPageNum() - 1 : 0);
        respVO.setNextPage(reqVO.getPageNum() < respVO.getPages() ? reqVO.getPageNum() + 1 : 0);
        respVO.setIsFirstPage(reqVO.getPageNum() == 1);
        respVO.setIsLastPage(reqVO.getPageNum().equals(respVO.getPages()));
        respVO.setHasPreviousPage(reqVO.getPageNum() > 1);
        respVO.setHasNextPage(reqVO.getPageNum() < respVO.getPages());

        // 汇总信息
        MajorRecommendRespVO.SummaryVO summary = new MajorRecommendRespVO.SummaryVO();
        summary.setUserScore(reqVO.getScore());
        summary.setUserRank(userRank);
        summary.setProvince(reqVO.getProvince());
        summary.setExamType(reqVO.getClassify() + "类");
        summary.setSubjectCombination(reqVO.getSubjects().replace(",", "+"));
        summary.setChongCount(chongCount);
        summary.setWentuoCount(wentuoCount);
        summary.setBaodiCount(baodiCount);
        summary.setAnalysisText(String.format("基于您的分数%d分，位次%d名，为您推荐%d个专业",
                reqVO.getScore(), userRank != null ? userRank : 0, total));
        respVO.setSummary(summary);

        return respVO;
    }
}
